package com.qinyi.framework.shiro.web.online;

import com.qinyi.system.domin.SysUser;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MapCache;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @author wangan on 2019/6/5
 * @description
 */
public class OnlineSessionFilter extends AccessControlFilter {

    public static final Logger log = LoggerFactory.getLogger(OnlineSessionFilter.class);

    @Autowired
    private EhCacheManager cacheManager;
    /**
     * 强制退出后重定向的地址
     */
    @Value("${shiro.user.loginUrl}")
    private String loginUrl;
    private Cache<String, Deque<Serializable>> cache;
    private int maxSession = 1;


    /**
     * 1.查询用户是否认证，如果没认证，继续后续操作
     * 2.如果用户已经登陆，判断用户超时时间,超时，则退出
     * 如果用户
     *
     * @param request
     * @param response
     * @param mappedValue
     * @return
     * @throws Exception
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        Subject subject = getSubject(request, response);
        if (!subject.isAuthenticated() && !subject.isRemembered()) {
            return true;
        }
        Session session = subject.getSession();
        log.debug("==session时间设置：" + session.getTimeout() + "===========");
        SysUser user = (SysUser) subject.getPrincipal();
        String username = user.getUserName();
        log.debug("===当前用户username：==" + username);
        cache = cacheManager.getCache("activeSessionCache");
        Deque<Serializable> deque = cache.get(username);
        Serializable id = subject.getSession().getId();
        if (deque == null) {
            deque = new ArrayDeque<>();
        }
        if (!deque.contains(id)) {
            deque.push(id);
            cache.put(username, deque);
        }
        while (deque.size() > maxSession) {
            deque.removeLast();
            cache.put(username, deque);
            subject.logout();
            WebUtils.issueRedirect(request, response, loginUrl);
        }
        return true;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);
        if (subject != null) {
            subject.logout();
        }
        saveRequestAndRedirectToLogin(request, response);
        return false;
    }

    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        WebUtils.issueRedirect(request, response, loginUrl);
    }
}
